package com.atguigu.gulimall.product.service.impl;

import com.atguigu.common.constant.ProductConstant;
import com.atguigu.gulimall.product.dao.AttrAttrgroupRelationDao;
import com.atguigu.gulimall.product.dao.AttrGroupDao;
import com.atguigu.gulimall.product.dao.CategoryDao;
import com.atguigu.gulimall.product.entity.AttrAttrgroupRelationEntity;
import com.atguigu.gulimall.product.entity.AttrGroupEntity;
import com.atguigu.gulimall.product.entity.CategoryEntity;
import com.atguigu.gulimall.product.service.CategoryService;
import com.atguigu.gulimall.product.vo.AttrGroupRelationVO;
import com.atguigu.gulimall.product.vo.AttrRespVO;
import com.atguigu.gulimall.product.vo.AttrVO;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.product.dao.AttrDao;
import com.atguigu.gulimall.product.entity.AttrEntity;
import com.atguigu.gulimall.product.service.AttrService;
import org.springframework.transaction.annotation.Transactional;


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    AttrAttrgroupRelationDao attrAttrgroupRelationDao;

    @Autowired
    AttrDao attrDao;

    @Autowired
    AttrGroupDao attrGroupDao;


    @Autowired
    CategoryDao categoryDao;

    @Autowired
    CategoryService categoryService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<AttrEntity>()
        );

        return new PageUtils(page);
    }

    //自定义保存属性
    @Transactional
    @Override
    public void saveAttr(AttrVO attr) {
        //1.创建po对象保存到数据库中
        AttrEntity attrEntity = new AttrEntity();
        //使用spring提供的BeanUtils.copyProperties(源，目标)完成vo属性值拷贝到po
        //使用前提-Vo中属性名和Po中相同
        BeanUtils.copyProperties(attr,attrEntity);
        this.save(attrEntity);

        //2.保存关联关系 - 注入AttrAttrgroupRelationDao
        //2.1 进一步改造 探讨是否是基本属性调用 如果是基本属性则保存关联关系
        //设定上销售属性不添加分组
        //注意属性分组Id也要判空
        if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getTypeCode() && attr.getAttrGroupId() != null){
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            //主要接收属性Id和属性分组ID
            relationEntity.setAttrGroupId(attr.getAttrGroupId());
            relationEntity.setAttrId(attrEntity.getAttrId());
            attrAttrgroupRelationDao.insert(relationEntity);
        }


    }

    @Override
    public PageUtils queryBaseListPage(Map<String, Object> params, Long catelogId, String type) {
        //①创建询条件
        //进一步改造 销售属性复用基本属性模块
        //增加type参量后进一步拼接新的条件 --三元拼接换参数类型
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type", "base".
                equalsIgnoreCase(type) ? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getTypeCode() :
                ProductConstant.AttrEnum.ATTR_TYPE_SALE.getTypeCode());
        //②分类讨论拼接条件 catelogId==0?params.key isEmpty?
        if (catelogId != 0){
            //查询指定三级分类标签下的属性
            queryWrapper.eq("catelog_id",catelogId);
        }
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            //attr_id  attr_name
            queryWrapper.and((wrapper)->{
                wrapper.eq("attr_id",key).or().like("attr_name",key);
            });
        }
        //③创建分页信息 传入包含分页信息的请求参数集合以及查询条件
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                queryWrapper
        );
        //④从page中得到数据库中查询到的记录 进行二次封装将分组名和分类名封装到attrRespVO中
        List<AttrEntity> records = page.getRecords();
        //流式编程
        List<AttrRespVO> respVOS = records.stream().map((attrEntity -> {
            //创建attrRespVO对象并拷贝信息
            AttrRespVO attrRespVO = new AttrRespVO();
            BeanUtils.copyProperties(attrEntity, attrRespVO);
            //查询并设置所属分组名
            //先根据关联表查出分组Id 再根据分组Dao查到分组名并设置进去
            AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
            //非空判断 由于属性在新增时分组可以不选所以有可能为空
            if (relationEntity != null && relationEntity.getAttrGroupId()!=null) {
                //获取分组ID并查设分组名
                Long attrGroupId = relationEntity.getAttrGroupId();
                AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
                if (attrGroupEntity!=null){
                    attrRespVO.setGroupName(attrGroupEntity.getAttrGroupName());
                }
            }

            //查询并设置所属分类名
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
            if (categoryEntity != null) {
                attrRespVO.setCatelogName(categoryEntity.getName());
            }

            return attrRespVO;
        })).collect(Collectors.toList());

        //⑤将page信息封装并重新设置结果集 将重新封装好的respVOS设置为结果集
        PageUtils pageUtils = new PageUtils(page);
        pageUtils.setList(respVOS);

        return pageUtils;
    }

    @Override
    public AttrRespVO getAttrInfo(Long attrId) {
        //查询PO
        AttrEntity attrEntity = this.getById(attrId);
        System.out.println(attrEntity);
        //创建VO并拷贝
        AttrRespVO attrRespVO = new AttrRespVO();
        BeanUtils.copyProperties(attrEntity,attrRespVO);

        //复用的改造 探讨是否是基本属性调用
        if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getTypeCode()){
            //分组
            AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
            if (relationEntity!=null && relationEntity.getAttrGroupId()!=null){
                attrRespVO.setAttrGroupId(relationEntity.getAttrGroupId());
                AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(relationEntity.getAttrGroupId());
                System.out.println("attrGroupEntity:"+attrGroupEntity);
                if (attrGroupEntity!=null){
                    attrRespVO.setGroupName(attrGroupEntity.getAttrGroupName());
                }
            }
        }

        //标签名
        CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
        if (categoryEntity!=null){
            attrRespVO.setCatelogName(categoryEntity.getName());
        }
        //完整路径
        //这里之前Category业务层自定义过一个方法根据分类catId获取携带完整路径的方法 注入
        //categoryService 方便起见注入service 略微不规范
        Long[] catelogPath = categoryService.findCatelogPath(categoryEntity.getCatId());
        attrRespVO.setCatelogPath(catelogPath);
        System.out.println(attrRespVO);
        return attrRespVO;
    }

    @Transactional
    @Override
    public void updateAttr(AttrVO attr) {
        //PO
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr,attrEntity);
        this.updateById(attrEntity);

        //进一步改造 基本属性和销售属性复用
        if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getTypeCode()){
            //修改分组关联表
            //注意 如果之前就没有给当前属性设置分组 那么此次操作就是新增
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            relationEntity.setAttrId(attr.getAttrId());
            relationEntity.setAttrGroupId(attr.getAttrGroupId());
            QueryWrapper<AttrAttrgroupRelationEntity> queryWrapper = new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId());
            Integer count = attrAttrgroupRelationDao.selectCount(queryWrapper);
            if (count > 0){
                //修改操作
                attrAttrgroupRelationDao.update(relationEntity, queryWrapper);
            }else {
                //新增操作
                attrAttrgroupRelationDao.insert(relationEntity);
            }
        }

    }

    //通过属性分组Id获取关联属性的信息 基本属性|规格参数
    @Override
    public List<AttrEntity> getRelationAttr(Long attrgroupId) {
        //通过关联表查出当前分组Id的所有关联实体类
        List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrgroupId));
        //取出所有属性Id
        List<Long> attrIds = relationEntities.stream().map((relationEntity) -> {
            return relationEntity.getAttrId();
        }).collect(Collectors.toList());
        //判断属性ID数组是否为空  不能用attrIds != null批断 这里数组必定
        if (attrIds.size()>0){
            //根据属性Ids查出所有属性集合
            Collection<AttrEntity> attrEntities = this.listByIds(attrIds);
            return (List<AttrEntity>) attrEntities;
        }
        //属性ID集合为空
        return null;
    }

    //根据AttrGroupRelationVO[]删除关联关系
    @Override
    public void deleteRelation(AttrGroupRelationVO[] vos) {
        //如果都按如下方式逐个删除咋需要访问很多次数据库，占用资源太多。
//        attrAttrgroupRelationDao.delete(new QueryWrapper<AttrAttrgroupRelationEntity>().
////                eq("attr_id",1L).and().eq("attr_group_id",1L));
        //Dao层自定义一个批量删除的方法
        //由于Dao层操作的都是PO类 所以将vos重新映射为POs --规范操作
        List<AttrAttrgroupRelationEntity> relationEntities = Arrays.asList(vos).stream().map((vo) -> {
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(vo, relationEntity);
            return relationEntity;
        }).collect(Collectors.toList());
        attrAttrgroupRelationDao.deleteBatchRelation(relationEntities);

    }

    /**
     * 获取当前分组未关联的无关联状态的属性
     * @param params
     * @param attrgroupId
     * @return
     */
    @Override
    public PageUtils getNoRelation(Map<String, Object> params, Long attrgroupId) {
        //1.当前分组只能关联自己所属的分类里的所有属性 先查出所属分类Id
        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrgroupId);
        Long catelogId = attrGroupEntity.getCatelogId();

        //2.当前分组只能关联别的分组没有引用的属性
        //2.1 查出当前分类下的所有属性分组
        List<AttrGroupEntity> allAttrGroupEntities = attrGroupDao.selectList(new QueryWrapper<AttrGroupEntity>().
                eq("catelog_id", catelogId));
        List<Long> allAttrGrpIds = allAttrGroupEntities.stream().map((attrGrp -> {
            return attrGrp.getAttrGroupId();
        })).collect(Collectors.toList());

        //2.2通过属性属性分组关联表查找所有属性分组存在关联的属性Id
        //先从中间表查出关联的中间Bean
        List<AttrAttrgroupRelationEntity> anotherAttrAgRels = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", allAttrGrpIds));
        //流式编程取出attrId
        List<Long> anotherAttrIds = anotherAttrAgRels.stream().map((attrAg) -> {
            return attrAg.getAttrId();
        }).collect(Collectors.toList());

        //2.3查找当前属性分组可以关联的属性 即当前分组的所有attrId不在anotherAttrIds中即可
        //this.baseMapper 相当于注入了attrDao 这里已经注入
        //构造查询条件 ①查出当前分类ID下的所有基本属性 ②属性ID不在anotherAttrIds中的即为可绑定属性
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
                eq("catelog_id", catelogId).eq("attr_type",ProductConstant.AttrEnum.ATTR_TYPE_BASE.getTypeCode());
        //拼接.notIn("attr_id", anotherAttrIds);前要先判断anotherAttrIds是否为空且数组长度大于0
        if (anotherAttrIds != null && anotherAttrIds.size()>0){
            queryWrapper.notIn("attr_id", anotherAttrIds);
        }
        //请求参数中有key 判断key是否为空进而拼装新的查询条件
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            //拼接模糊查询条件 注意用and(函数式编程)
            queryWrapper.and((wrapper)->{
                wrapper.eq("attr_id",key).or().like("attr_name",key);
            });
        }
        //调用page方法封装为Ipage
        IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), queryWrapper);
        return new  PageUtils(page);
    }

}